#!/usr/bin/env sh
#
# ~~ Protonator: a ProtonVPN connect script ~~
#
# License:
#   - This script: MIT (Expat)
#   - update-resolv-conf.sh (downloaded automatically): GNU GPL

# Check if a command exists on system
#   - $1: command to check if it exists
command_exists() {
	if type "$1" >/dev/null 2>&1; then
		return 0
	else
		return 1
	fi
}

# Check requirements
if ! command_exists 'openvpn'; then
	echo 'Error: OpenVPN is not installed. Please install it and try again.'
	exit 1272
else
	if [ "$SHELL" = '/bin/bash' ] || [ "$SHELL" = '/usr/local/bin/bash' ]; then
		openvpn_version="$(openvpn --version)"
		openvpn_version="${openvpn_version#OpenVPN *}"
		openvpn_version="${openvpn_version%%.*}"
	else
		openvpn_version=$( openvpn --version | head -n 1 | \
			awk '{ print $2 }' | awk -F'.' '{ print $1 }' )
	fi
	if [ "$openvpn_version" != '2' ]; then
		echo "Error: Currently only OpenVPN v2 is supported" \
			"but v${openvpn_version} is installed."
		exit 1247
	fi
fi

# Program to use for root priviledges
if command_exists 'sudo'; then
	subin='sudo'
elif command_exists 'doas'; then
	subin='doas'
else
	echo 'Error: sudo or doas not found... exiting...'
	exit 1235
fi

# Set selection to none
chosen=''

# Going to start file based operations, so cd into script directory so that
# relative paths can be used safely. This would allow script to be run from
# other directories without messing up things.
cd "$(dirname "$0")"

# If config/config.sh exists, source it to take values from it
[ -f 'config/config.sh' ] && . 'config/config.sh'

# Show CLI based menu (without dmenu, fzf or other GUI tools)
shell_menu () {
	file_list=$( cd ovpns; ls *.ovpn )
	menu=$( echo "$file_list" | cat -n | column -c 100 | sed 's/\t/ /g' )
	echo "$menu"
	echo -n 'Enter the number beside the ovpn config filename to connect: '
	read selection

	chosen=$( echo "$file_list" | sed -n "${selection}p" )
}

# If there's no menu chooser installed, fallback to shell selection.
if [ -z "$DISPLAY" ] || \
	( ! command_exists 'fzf' && ! command_exists 'dmenu' && \
	! command_exists 'rofi' ); then
	shell_menu
else
	chosen=$( cd ovpns; ls *.ovpn | \
		(fzf || dmenu || rofi -dmenu -i) 2>/dev/null )
fi

# If nothing is chosen, exit script, otherwise continue
if [ -z "$chosen" ]; then
	echo 'Cancelled menu selection... exiting...'
	exit 1
fi
echo "Chosen to connect to $chosen ..."

# Create '/etc/openvpn/update-resolv-conf' if it does not exist
# Source: https://protonvpn.com/support/linux-vpn-setup/
update_resolv_conf_file='/etc/openvpn/update-resolv-conf'
if [ ! -f "$update_resolv_conf_file" ]; then
	echo "$update_resolv_conf_file not found ..."
	echo 'Downloading update-resolv-conf and installing it to /etc/openvpn ...'
	[ ! -d '/etc/openvpn' ] && $subin mkdir -p '/etc/openvpn'
	update_resolv_conf_url='https://raw.githubusercontent.com/ProtonVPN/scripts/master/update-resolv-conf.sh'
	if command_exists 'wget'; then
		$subin wget "$update_resolv_conf_url" -O "$update_resolv_conf_file"
	elif command_exists 'curl'; then
		$subin curl -L "$update_resolv_conf_url" -o "$update_resolv_conf_file"
	else
		echo 'Error: curl or wget not found... could not download... exiting...'
		exit 1224
	fi
	if [ "$?" = '0' ]; then
		$subin chmod +x "$update_resolv_conf_file"
	else
		echo 'Download was not successful... exiting...'
		exit 1227
	fi
fi

# Proceed with connect process
if [ -f 'config/cred.aes' ]; then
	# If cred.aes is found, we use it. Requires passphrase, but superior to
	# other options.
	# To encrypt:
	# openssl aes-256-cbc -pbkdf2 -iter 25763 -salt -in config/cred.txt -out config/cred.aes -e -a && rm config/cred.txt
	DEC=$(openssl aes-256-cbc -pbkdf2 -iter 25763 -in config/cred.aes -d -a)
	# Separate line with variable is to address mess up of sudo/doas password
	# prompt with openssl one at the same time.
	echo "$DEC" | $subin openvpn --config "ovpns/$chosen" \
		--auth-user-pass /dev/stdin $openvpn_cli_arguments_append
	# Discard the decrypted data because it's not needed anymore.
	unset DEC
elif [ -f 'config/cred.enc' ]; then
	# If cred.enc is found, we use it.
	# To encrypt:
	# openssl enc -pbkdf2 -salt -in config/cred.txt -out config/cred.enc -e -a && rm config/cred.txt
	openssl enc -pbkdf2 -in config/cred.enc -d -a | $subin openvpn \
		--config "ovpns/$chosen" --auth-user-pass /dev/stdin \
		$openvpn_cli_arguments_append
elif [ -f 'config/cred.txt' ]; then
	# If pass.txt is found, we use it.
	$subin openvpn --config "ovpns/$chosen" --auth-user-pass 'config/cred.txt' \
		$openvpn_cli_arguments_append
else
	# If saved cred.txt is not found, we just connect to the config and user
	# will be asked for username and passphrase.
	$subin openvpn --config "ovpns/$chosen" $openvpn_cli_arguments_append
fi
